<?php

namespace App\Admin;

use App\Admin\Traits\ModelTree;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Database\Eloquent\Model;

class Tree implements Renderable
{
    /**
     * 树结构所有节点
     *
     * @var array
     */
    protected $items = [];

    /**
     * 节点的html元素id前缀
     *
     * @var string
     */
    protected $elementId = 'tree-';

    /**
     * 数据模型
     *
     * @var Model
     */
    protected $model;

    /**
     * 构建树结构数据查询的回调
     *
     * @var \Closure
     */
    protected $queryCallback;

    /**
     * 树结构相关的模版名
     *
     * @var array
     */
    protected $view = [
        'tree'   => 'admin.tree',
        'branch' => 'admin.tree.branch',
    ];

    /**
     *
     *
     * @var \Closure
     */
    protected $callback;

    /**
     * 该回调返回要在页面上每条记录显示的内容
     *
     * @var null|\Closure
     */
    protected $branchCallback = null;

    /**
     * 是否有添加按钮
     *
     * @var bool
     */
    public $useCreate = true;

    /**
     * 前端nestable插件的设置项
     *
     * @var array
     */
    protected $nestableOptions = [];

    /**
     * 该树结构所在页面网址的路径
     *
     * @var string
     */
    protected $path;

    /**
     * Tree constructor.
     * @param Model|null $model
     * @param \Closure|null $callback
     */
    public function __construct(Model $model = null, \Closure $callback = null)
    {
        $this->model = $model;

        $this->path = \Route::current()->uri();
        $this->elementId .= uniqid();

        if ($callback instanceof \Closure) {
            call_user_func($callback, $this);
        }

        $this->initBranchCallback();
    }

    /**
     * 初始化页面上每个结点要显示的内容为"$key - $title"
     */
    protected function initBranchCallback()
    {
        if (is_null($this->branchCallback)) {
            $this->branchCallback = function ($branch) {
                $key = $branch[$this->model->getKeyName()];
                $title = $branch[$this->model->getTitleColumn()];

                return "$key - $title";
            };
        }
    }

    /**
     * 自定义页面上每个结点要显示的内容为的回调
     *
     * @param \Closure $branchCallback
     * @return $this
     */
    public function branch(\Closure $branchCallback)
    {
        $this->branchCallback = $branchCallback;

        return $this;
    }

    /**
     * 设置树结构数据的查询回调
     *
     * @param \Closure $callback
     * @return $this
     */
    public function query(\Closure $callback)
    {
        $this->queryCallback = $callback;

        return $this;
    }

    /**
     * 设置前端树结构的设置项
     *
     * @param array $options
     * @return $this
     */
    public function nestable($options = [])
    {
        $this->nestableOptions = array_merge($this->nestableOptions, $options);

        return $this;
    }

    /**
     * 隐藏树结构页面中的添加按钮
     */
    public function disableCreate()
    {
        $this->useCreate = false;
    }

    /**
     * 按请求中的数据保存树结构的结构
     *
     * @param $serialize
     * @return bool
     */
    public function saveOrder($serialize)
    {
        $tree = json_decode($serialize, true);

        if (json_last_error() != JSON_ERROR_NONE) {
            throw new \InvalidArgumentException(json_last_error());
        }

        $this->model->saveOrder($tree);

        return true;
    }

    /**
     * 树结构的js
     *
     * @return string
     */
    public function script()
    {
        $confirm = '子项目也将被删除，确认删除？';

        $nestableOptions = json_encode($this->nestableOptions);

        return <<<SCRIPT
        
        $('#{$this->elementId}').nestable($nestableOptions);
        
        $('.tree_branch_delete').click(function () {
            var id = $(this).data('id');
            layer.confirm('{$confirm}', {icon: 0, title:'警告'}, function (index) {
                $.post('/{$this->path}/' + id, {_method: 'delete', '_token': laravel.token}, function (data) {
                    if (data.status) {
                        location.reload();
                    }
                });
                
                layer.close(index);
            });
        });
        
        $('.{$this->elementId}-save').click(function () {
            var self = $(this);
            var serialize = $('#{$this->elementId}').nestable('serialize');

            var sc = submitControl();
            sc.setInputs(self);
            $.ajax({
                submitControl: sc,
                url: '/{$this->path}',
                method: 'post',
                data: {
                    _token: laravel.token,
                    _order: JSON.stringify(serialize),
                },
            }).done(function (res) {
                if (res.status) {
                    sc.setReset({
                        form: false,
                        status: false,
                    });
                    location.reload();
                }
            });
        });
        
        $('.{$this->elementId}-tree-tools').on('click', function(e){
            var target = $(e.target);
            var action = target.data('action');
            
            if (action === 'expand') {
                $('.dd').nestable('expandAll');
            }
            if (action === 'collapse') {
                $('.dd').nestable('collapseAll');
            }
        });

SCRIPT;
    }

    /**
     * 自定义树结构的页面模板
     *
     * @param $view
     */
    public function setView($view)
    {
        $this->view = $view;
    }

    public function variables()
    {
        return [
            'id'        => $this->elementId,
            'items'     => $this->model->withQuery($this->queryCallback)->toTree(),
            'useCreate' => $this->useCreate,
        ];
    }

    /**
     * 构建树结构页面
     *
     * @return \Illuminate\Http\JsonResponse|string
     * @throws \Throwable
     */
    public function render()
    {
        Admin::script($this->script());

        view()->share([
            'path'             => $this->path,
            'keyName'          => $this->model->getKeyName(),
            'branchView'       => $this->view['branch'],
            'branchCallback'   => $this->branchCallback,
            'parentColumnName' => $this->model->getParentColumn(),
        ]);

        return view($this->view['tree'], $this->variables())->render();
    }

    /**
     * 返回构建好的树结构页面字符串
     *
     * @return \Illuminate\Http\JsonResponse|string
     * @throws \Throwable
     */
    public function __toString()
    {
        return $this->render();
    }

    /**
     * 判断一个模型实例是不是属于Tree类型
     * 如果使用了ModelTree 这个Trait 则是的
     *
     * @param Model $model
     * @return bool
     * @throws \ReflectionException
     */
    public static function isTree(Model $model)
    {
        $reflectionClass = new \ReflectionClass($model);

        return in_array(ModelTree::class, $reflectionClass->getTraitNames());
    }
}